home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Messaging / OSL / OSLBldSt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  28.6 KB  |  958 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        OSLBldSt.c (Orignal name: OSLBuildStructs.c)
  3.  
  4.     Contains:    
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1992 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>     1/15/96    TJ        Cleaned Up
  13.          <4>     1/12/95    jpa        Don't use obsolete Toolbox names [1211211]
  14.          <3>    11/15/94    NP        1191221-added warning at call of PtrToHand.
  15.          <2>     8/19/94    NP        1181622: Ownership fix.
  16.          <7>      5/2/94    eeh        bug #1160654: various PPC native changes
  17.          <6>     11/2/93    NP        Moved back pascal keyword for MPW C.
  18.          <5>     11/2/93    NP        Move pascal keyword.
  19.          <4>    10/22/93    NP        Removed unnecessary assignment, and thus,
  20.                                     compiler warning.
  21.          <3>     7/28/93    NP        Mods for new token type, OSLToken.
  22.          <2>     7/21/93    NP        Fixed #includes.
  23.          <1>     7/21/93    NP        first checked in
  24.  
  25.     To Do:
  26.     In Progress:
  27. */
  28.  
  29. #include "OSLPriv.h"
  30. #include <SetJmp.h>
  31.  
  32. #pragma segment AEObjSuppt
  33.  
  34. static OSErr
  35. ClearNewHandle( Handle *theH, long size )
  36. {
  37.         *theH = NewHandleClear( size ) ;
  38.         return MemError() ;
  39. }
  40.  
  41.  
  42.  
  43. ///////////////////////////////////////////////////////////////////////////////
  44. // MakeWhoseDescriptor
  45. // packs the selection data for a 'whose' naming form. This type of naming
  46. // names the desired object by specifying an identifying test. This is
  47. // probably a pretty familiar form of utility by this point, but essentially
  48. // it makes up the record, fills in fields from the parameters, and packs them
  49. // into a descriptor.
  50. ///////////////////////////////////////////////////////////////////////////////
  51.  
  52. static OSErr
  53. MakeWhoseDescriptor(    AEDesc *indexOrRel, AEDesc *test, AEDesc* theDescriptor )
  54. {
  55.     AERecord whoseRecord ;
  56.     OSErr err = noErr ;
  57.     
  58.     err = AECreateList( NULL, 0, true, &whoseRecord ) ;        // create the record
  59.     if ( err != noErr ) goto L100 ;
  60.     
  61.     // the indexOrRel field, which says which object or objects that meet 
  62.     // the test are desired, this index can also be a relative record
  63.  
  64.     err = AEPutKeyDesc( &whoseRecord, keyAEIndex, indexOrRel ) ;
  65.     if ( err != noErr ) goto L100 ;
  66.  
  67.     // now we fill in the test we will use
  68.  
  69.     err = AEPutKeyDesc( &whoseRecord, keyAETest, test ) ;
  70.     if ( err != noErr ) goto L100 ;
  71.  
  72.     // dispose of input
  73.  
  74.     IgnoreOSErr( AEDisposeDesc( indexOrRel ) ) ;
  75.     IgnoreOSErr( AEDisposeDesc( test ) ) ;
  76.     
  77.     // coerce record to descriptor
  78.     err =  AECoerceDesc( &whoseRecord, typeWhoseDescriptor, theDescriptor ) ;
  79.     if ( err == noErr ) goto L200 ;
  80.  
  81. L100:
  82.     MakeNull( theDescriptor ) ;
  83. L200:
  84.     IgnoreOSErr( AEDisposeDesc( &whoseRecord ) ) ;
  85.     return err ;
  86. } // MakeWhoseDescriptor
  87.  
  88.  
  89.     /*———————————————————————— CreateCompare ————————————————————————*/
  90.  
  91. OSErr
  92. CreateCompare( AEDesc  input , Comparison *theComparison )
  93. /*create a comparison record from a descriptor of type typeCompDescriptor*/
  94. {
  95.     AERecord         tempRecord ;
  96.     DescType         ignoreReturnedType ;            /* <eeh> never checked */
  97.     long         actualSize ;
  98.     AEDesc         tempObject ;
  99.     OSErr          err ;
  100.  
  101.  
  102.     err = ClearNewHandle( (Handle *)theComparison, sizeof( CompareRecord ) ) ;
  103.     if ( err != noErr ) goto L100 ;
  104.     
  105.     /*            Using NewHandleClear saves the following calls:
  106.     WITH theComparison** DO
  107.     {
  108.     obj1 = NULL ;
  109.     obj2 = NULL ;
  110.     value = false ;
  111.     redo = false ;
  112.     } ; */
  113.     
  114.     HLock( (Handle)*theComparison ) ;
  115.     
  116.     err = AEDuplicateDesc( &input, &(**theComparison)->theCompInput ) ;
  117.     if ( err != noErr ) goto L200 ;
  118.     
  119.     err = AECoerceDesc( &input, typeAERecord, &tempRecord ) ;
  120.     if ( err != noErr ) goto L300 ;
  121.     
  122. //    WITH theComparison** DO
  123.     {
  124.         ComparePtr cp = **theComparison ;
  125.         
  126.         err = AEGetKeyPtr( &tempRecord, keyAECompOperator,
  127.                             typeEnumerated, &ignoreReturnedType,
  128.                             (Ptr)&cp->oper, sizeof(cp->oper), &actualSize ) ;
  129.         if ( err != noErr ) goto L350 ;
  130.         
  131.         err = AEGetKeyDesc( &tempRecord, keyAEObject1, typeWildCard, &tempObject ) ;
  132.         if ( err != noErr ) goto L350 ;
  133.         
  134.         err = CreateObject( &tempObject, NULL, true, &cp->obj1 ) ;        /* obj1 is NULL until set here */
  135.         if ( err != noErr ) goto L400 ;
  136.         
  137.         IgnoreOSErr( AEDisposeDesc( &tempObject ) )  ;
  138.         err = AEGetKeyDesc( &tempRecord, keyAEObject2, typeWildCard, &tempObject ) ;
  139.         if ( err != noErr ) goto L450 ;
  140.         
  141.         err = CreateObject( &tempObject, NULL, true, &cp->obj2 ) ;        /* obj2 is NULL until set here */
  142.         IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  143.         
  144.         /*okay, we've got all of the data, now we set the redo flag so that the first
  145.         time we evaluate the comparison, everything tries to evaluate at least once*/
  146.         cp->redo = true;
  147.     }
  148.     
  149.     IgnoreOSErr( AEDisposeDesc( &tempRecord ) )  ;
  150.     HUnlock( (Handle) *theComparison ) ;
  151.     
  152.     if ( err != noErr )
  153.     {
  154.     DisposeObj( (**theComparison)->obj2 ) ;
  155. L450:
  156.     DisposeObj( (**theComparison)->obj1 ) ;
  157. L400:
  158.     IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  159. L350:
  160.     IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  161. L300:
  162.     if ( SetErrDesc( (**theComparison)->theCompInput ) )
  163.         (**theComparison)->theCompInput.dataHandle = NULL ;
  164. L200:
  165.     DisposeHandle( (Handle)*theComparison ) ;
  166.     theComparison = NULL ;                                        /* 4/11 caller's fail will attempt a second dispose */
  167.     }
  168. L100:
  169.     
  170.     return err ;
  171.     
  172. } /*CreateCompare*/
  173.  
  174.     
  175.     /*———————————————————————— CreateLogical ————————————————————————*/
  176.  
  177. /*create a logical record from a descriptor of type typeLogicalDescriptor*/
  178. OSErr
  179. CreateLogical( const AEDesc *input , Logical *theLogical )
  180.         
  181. {
  182.     AERecord         tempRecord ;
  183.     AEDesc         tempList ;
  184.     long         nTerms ;
  185.     AEKeyword         ignoredKeyword ;
  186.     AEDesc         dThisTerm ;
  187.     Term         thisTerm ;
  188.     Term         lastTerm ;
  189.     DescType         theReturnedType ;
  190.     long         actualSize ;
  191.     long         I ;
  192.  
  193.     OSErr err = noErr;
  194.  
  195.     tempRecord.dataHandle = NULL;
  196.     tempList.dataHandle = NULL;
  197.     lastTerm = NULL;
  198.     
  199.     FailErr( ClearNewHandle( (Handle *)theLogical, sizeof(LogicalRecord) ),
  200.         err, errExit ) ;
  201.  
  202. /*            Using NewHandleClear saves the following calls:
  203. WITH theLogical** DO
  204. {
  205. firstTerm = NULL ;
  206. value = false ;
  207. redo = false ;
  208. } ; */
  209.  
  210.     HLock( (Handle) *theLogical ) ;
  211.     
  212.     FailErr( AEDuplicateDesc( input, &(**theLogical)->theLogicalInput ),
  213.             err, errExit ) ;
  214.     FailErr( AECoerceDesc(input, typeAERecord, &tempRecord), err, errExit);
  215.  
  216.     //WITH theLogical** DO
  217.     {
  218.         LogicalPtr lp = **theLogical ;
  219.     
  220.         FailErr( AEGetKeyPtr( &tempRecord, keyAELogicalOperator, typeEnumerated,
  221.                 &theReturnedType, (Ptr)&lp->logicalOp, sizeof(lp->logicalOp),
  222.                 &actualSize), err, errExit) ;
  223.     
  224.         FailErr( AEGetKeyDesc( &tempRecord, keyAELogicalTerms, typeWildCard,
  225.                 &tempList ), err, errExit ) ;
  226.         
  227.         FailErr( AECountItems( &tempList, &nTerms), err, errExit ) ;
  228.         
  229.         for( I = 1; I <=nTerms; ++I )        /* build a linked list of comparisons */
  230.         {
  231.             FailErr( AEGetNthDesc( &tempList, I, typeWildCard, &ignoredKeyword,
  232.                     &dThisTerm), err, errExit ) ;
  233.             FailErr( CreateTerm( &dThisTerm, &thisTerm ), err, errExit ) ;
  234.             
  235.             if ( lastTerm == NULL )
  236.             {
  237.                 lp->firstTerm = thisTerm;
  238.                 lastTerm = thisTerm;
  239.             }
  240.             else
  241.                 {
  242.                     (*lastTerm)->next = thisTerm;
  243.                     lastTerm = thisTerm;
  244.                 }
  245.             
  246.         } /*for*/
  247.             
  248.         /*set the redo flag so that everything tries to evaluate at least once*/
  249.         lp->redo = true;
  250.     }
  251.  
  252.     HUnlock( (Handle)*theLogical ) ;
  253.     
  254.     IgnoreOSErr( AEDisposeDesc( &tempRecord) ) ;
  255.     IgnoreOSErr( AEDisposeDesc( &tempList ) ) ;
  256.  
  257. FAIL_ERR_PROC(err, errExit)
  258.     if ( theLogical != NULL )
  259.     {
  260.         if ( SetErrDesc( (**theLogical)->theLogicalInput ) )
  261.             (**theLogical)->theLogicalInput.dataHandle = NULL ;
  262.         DisposeTerm( (**theLogical)->firstTerm) ;
  263.     };
  264.     DisposeHandle( (Handle)*theLogical ) ;
  265.     *theLogical = NULL;
  266.  
  267.     IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  268.     IgnoreOSErr( AEDisposeDesc( &tempList ) ) ;
  269.     IgnoreOSErr( AEDisposeDesc( &dThisTerm ) ) ;
  270. END_FAIL_ERR_PROC(err)
  271. } /*CreateLogical*/
  272.         
  273.  
  274.     /*———————————————————————— CreateObject ————————————————————————*/
  275.  
  276. extern pascal Boolean IsKnownAbso( DescType abso ) ;
  277.  
  278. /* RangeIsWhoseable: eeh 2/1/90
  279. Determine if ( a range can be converted to data that can be inserted into the structure for
  280. resolving whose descriptors; if ( it can, convert it to a special type desc and pass it
  281. back.
  282. */
  283. #define cleanupNow false
  284.  
  285. /* A bit different from the FailErr()s.  RangeIsWhoseable returns a Boolean 
  286.  * rather than an error, so I can use ExitIfNot to bail whenever, even to 
  287.  * clean up when there's been no error */
  288.  
  289.  
  290. static void
  291. ExitIfNot( Boolean b, jmp_buf *jbp )
  292. {
  293.     if ( !b )
  294.     {
  295.         longjmp( *jbp, 1 ) ;
  296.     }
  297. }
  298.  
  299. #define sizeZero  0
  300. static OSErr
  301. GetWhoseEndPoint( AEDesc dEndObj, long  *value , DescType *valCase,
  302.         AEDesc tempRIWRecord, DescType objClass, jmp_buf *jbp ) 
  303.  
  304. {
  305.     DescType                      theReturnedType ;
  306.     DescType                      scratch ;                    /* used as temporary storage for all sorts of tests */                
  307.     long                      actualSize ;
  308.     OSErr err = noErr ;
  309.     
  310.     IgnoreOSErr( AEDisposeDesc( &tempRIWRecord ) ) ;
  311.     FailErr( AECoerceDesc( &dEndObj, typeAERecord, &tempRIWRecord ),
  312.             err, errExit ) ;
  313.     FailErr( AEGetKeyPtr( &tempRIWRecord, keyAEContainer, typeWildCard,
  314.         &theReturnedType, NULL, sizeZero, &actualSize ), err, errExit ) ;
  315.     ExitIfNot( theReturnedType == typeCurrentContainer, jbp ) ;
  316.     FailErr( AEGetKeyPtr( &tempRIWRecord, keyAEDesiredClass, typeType,
  317.         &theReturnedType, (Ptr)&scratch, SizeOf(scratch), &actualSize),
  318.         err, errExit ) ;
  319.     ExitIfNot( scratch == objClass, jbp ) ;
  320.     FailErr( AEGetKeyPtr( &tempRIWRecord, keyAEKeyForm, typeEnumerated,
  321.         &theReturnedType, (Ptr)&scratch, sizeof(scratch), &actualSize),
  322.         err, errExit ) ;
  323.     ExitIfNot( scratch == formAbsolutePosition, jbp ) ;
  324.     FailErr( AEGetKeyPtr( &tempRIWRecord, keyAEKeyData, typeWildCard, valCase,
  325.         (Ptr)value, sizeof(*value), &actualSize), err, errExit ) ;
  326.     ExitIfNot( (actualSize == sizeof(value)) 
  327.                 && ((*valCase == typeAbsoluteOrdinal)
  328.                 || (*valCase == typeLongInteger)), jbp ) ;
  329.  
  330. FAIL_ERR_PROC(err, errExit)
  331. END_FAIL_ERR_PROC(err)
  332. }  /* GetWhoseEndPoint */
  333.  
  334.  
  335. static Boolean
  336. RangeIsWhoseable( DescType objClass, AEDesc rangeDesc,
  337.     IndexRecord *index, OSErr *externalErr ) 
  338. {
  339.     AEDesc dStartObj, dStopObj ;
  340.     AEDesc                  tempRIWRecord ;
  341.     OSErr                  err ;
  342.     Boolean retVal = false ;
  343.     jmp_buf jb ;
  344.     
  345.     dStartObj.dataHandle = NULL ;
  346.     dStopObj.dataHandle = NULL ;
  347.     tempRIWRecord.dataHandle = NULL ;
  348.  
  349.     *externalErr = noErr ;
  350.  
  351.     if (setjmp( jb) )        // we'll come back here if it is determined that
  352.     {                                    // the answer is false
  353. //        IgnoreOSErr( AEDisposeDesc( &tempRIWRecord ) ) ;
  354. //        IgnoreOSErr( AEDisposeDesc( &dStartObj ) ) ;
  355. //        IgnoreOSErr( AEDisposeDesc( &dStopObj ) ) ;
  356.         retVal = false ;
  357.         err = noErr ;
  358.         goto errExit ;                // not really an error, but...
  359.     }                    
  360.  
  361.     FailErr( AECoerceDesc( &rangeDesc, typeAERecord, &tempRIWRecord ),
  362.             err, errExit ) ;
  363.     
  364.     FailErr( AEGetKeyDesc( &tempRIWRecord, keyAERangeStart, typeWildCard,
  365.             &dStartObj ), err, errExit  ) ;
  366.     FailErr( AEGetKeyDesc( &tempRIWRecord, keyAERangeStop, typeWildCard,
  367.         &dStopObj ), err, errExit ) ;
  368.  
  369.     FailErr( GetWhoseEndPoint( dStartObj, &index->startValue, &index->startCase, 
  370.             tempRIWRecord, objClass, (jmp_buf *)&jb ), err, errExit ) ;
  371.     FailErr( GetWhoseEndPoint( dStopObj, &index->stopValue, &index->stopCase,
  372.             tempRIWRecord, objClass, (jmp_buf *)&jb ), err, errExit ) ;
  373.     
  374.     retVal = true ;            /* if we've gotten this far, it's true */
  375. //    ExitIfNot( cleanupNow ) ;
  376.  
  377.  
  378. errExit :
  379.     IgnoreOSErr( AEDisposeDesc( &dStartObj) ) ;
  380.     IgnoreOSErr( AEDisposeDesc( &dStopObj) ) ;
  381.     IgnoreOSErr( AEDisposeDesc( &tempRIWRecord) ) ;
  382.     *externalErr = err ;
  383.     return retVal ;
  384.  
  385. }  /* RangeIsWhoseable */
  386.  
  387.  
  388. /* CombineObjects:
  389.  * this could be done without parameters, but I find this style much easier
  390.  * to read and to maintain.
  391.  * Combines two objects into one.  On entry, objWithTest has selectionData
  392.  * that needs to be moved to objWithIndex, whose selectionData should
  393.  * already have been disposed of.
  394. */
  395. static void
  396. CombineObjects( Object *objWithTest, Object *objWithIndex )
  397. {
  398.     Object tempContainerH ;            /* used for swapping */
  399.  
  400. //WITH objWithTest** DO
  401.     {
  402.         ObjRecordPtr orp = **objWithTest ;
  403.     
  404.         IgnoreOSErr( AEDisposeDesc( &orp->theObjInput ) ) ;
  405.         (**objWithIndex)->u.objForm = formWhose ;
  406.         (**objWithIndex)->objContainer = orp->objContainer ;
  407.         (**objWithIndex)->objSelectionData = orp->objSelectionData ;
  408.         if ( orp->objContainer != NULL )
  409.             (*(orp->objContainer))->objContained = *objWithIndex ;
  410.         tempContainerH = orp->objContainer ;                                            
  411.         orp->objContainer = NULL ;                                /* so DisposeObj doesn't follow the chain */
  412.         orp->objSelectionData.dataHandle = NULL ;            /* " */
  413.         DisposeObj( *objWithTest ) ;
  414.     }
  415.  
  416.     *objWithTest = tempContainerH ;                                    /* so the current makeobj call returns right values */
  417. }  /* CombineObjects */
  418.  
  419.  
  420. /*create a term record from either a typeLogicalDescriptor or a typeCompDescriptor.
  421.  Do not dispose input: app may own it.*/
  422. OSErr
  423. CreateObject( const AEDesc  *input , Object  containedObj,
  424.         Boolean  expandWhoseData, Object *theObject )
  425.         
  426.     {
  427.     AEDesc          tempObject ;
  428.     AEDesc          tempRecord ;
  429.     DescType          theReturnedType ;
  430.     Size          actualSize;
  431.     Object          newObj ;
  432.     Boolean          canCombine ;
  433.     //Boolean          disposedSelf ;            /* if dispose self for optimization, don't unlock Handle! */
  434.     IndexRecord         index ; 
  435.     
  436.     
  437.     OSErr err = noErr;
  438.     
  439.     tempObject.dataHandle = NULL;
  440.     tempRecord.dataHandle = NULL;
  441.     
  442.     FailErr( ClearNewHandle( (Handle *)&newObj, sizeof(ObjRecord) ), err, errExit ) ;
  443.     
  444.     /*            Using NewHandleClear saves the following calls:
  445.     WITH newObj** DO
  446.     {
  447.     objContainer = NULL ;
  448.     objContained = NULL ;
  449.     objSelectionData.dataHandle = NULL ;
  450.     objTheWhose = NULL ;
  451.     objValue.dataHandle = NULL ;
  452.     valIsExmn = false ;
  453.     objRedo = false ;
  454.     } ; */
  455.     
  456.     /* <eeh> 4/8 does it really make sense to put a copy of the desc in the record in any case
  457.     but that where it is an object.  Who cares what the input is when it's a text descriptor.
  458.     And will we look pretty silly returning ['text', "spinnaker"] when a memory error occurs? */
  459.     
  460.     (*newObj)->objContained = containedObj ;
  461.     (*newObj)->objValue.descriptorType = typeNull ;
  462.     
  463.     /*set the redo flag so that everything tries to evaluate at least once*/
  464.     (*newObj)->objRedo = true;
  465.     
  466.     HLock( (Handle)newObj ) ;
  467.     
  468.     FailErr( AEDuplicateDesc( input, &(*newObj)->theObjInput ), err, errExit ) ;
  469.     
  470.     switch( input->descriptorType )
  471.     {
  472.     case typeNull:
  473.         (*newObj)->objClass = typeNull ;
  474.         break ;
  475.     
  476.     
  477.     case typeToken :    /* 4/4; dataHandle is to a token descriptor */
  478.     //    WITH newObj** DO
  479.         (*newObj)->objValue = 
  480.                 (*(ContainedTokenRecHandle)(input->dataHandle))->token ;
  481.         (*newObj)->u.tokenClass =
  482.                 (*(ContainedTokenRecHandle)(input->dataHandle))->tokenClass ;
  483.         (*newObj)->objClass = typeToken ;
  484.         (*newObj)->objRedo = false;
  485.         break ;
  486.     
  487.     case typeObjectBeingExamined :
  488.         (*newObj)->objClass = typeObjectBeingExamined ;
  489.         break ;
  490.     
  491.     case typeObjectSpecifier :
  492.         FailErr( AECoerceDesc( input, typeAERecord, &tempRecord ), err, errExit ) ;
  493.     
  494.     //WITH newObj** DO
  495.     /*get the selector form*/
  496.         {
  497.             ObjRecordPtr op = *newObj ;
  498.     
  499.             FailErr( AEGetKeyPtr( &tempRecord, keyAEKeyForm, typeEnumerated,
  500.                     &theReturnedType, (Ptr)&op->u.objForm, sizeof(op->u.objForm),
  501.                     &actualSize), err, errExit ) ;
  502.             
  503.             /*get the desired type*/
  504.             
  505.             FailErr( AEGetKeyPtr( &tempRecord, keyAEDesiredClass, typeType, 
  506.                     &theReturnedType, (Ptr)&op->objClass, SizeOf(op->objClass), &actualSize),
  507.                     err, errExit ) ;
  508.             
  509.             /*get the selector data; put it in the object record so recursive call can get it.*/
  510.             FailErr( AEGetKeyDesc( &tempRecord, keyAEKeyData, typeWildCard,
  511.                     &op->objSelectionData ), err, errExit ) ;
  512.             
  513.             /* 
  514.             HERE IS WHERE WE RECURSIVELY CALL OURSELVES.
  515.             Optimization may occur here. Get the container object.
  516.             */
  517.             
  518.             FailErr( AEGetKeyDesc( &tempRecord, keyAEContainer, typeWildCard,
  519.                     &tempObject ), err, errExit ) ;
  520.             FailErr( CreateObject( &tempObject, newObj, expandWhoseData,
  521.                     &op->objContainer ), err, errExit ) ;
  522.             IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  523.             
  524.             /* Now look at the selector data (which may have been altered by the recursive CreateObject
  525.             call) and if ( it is a whose ) create the test record.  if ( we don't want to dispose of
  526.             the selectionData, set tempObject's Handle to NULL. */
  527.             
  528.             if ( (op->u.objForm == formWhose) && expandWhoseData )
  529.             {
  530.                 FailErr( CreateWhose( op->objSelectionData,
  531.                         (Whose*)&op->objTheWhose ), err, errExit )     ;
  532.                 IgnoreOSErr( AEDisposeDesc( &op->objSelectionData ) ) ;
  533.             }
  534.         
  535.             /* else do nothing: the selectionData already holds tempObject */
  536.             
  537.             /* Now look for simplifications that can/must be done.  If the class of object and its
  538.             container are the same there is the possibility of combining the two operations into
  539.             one.  if ( the form is formTest we MUST optimize; if ( the form of the contained is 
  540.             formAbsolutePosition we can combine the two; if ( it is anything else (for now) we convert the
  541.             test to a phony whose-clause with kAEAll as its index field. */
  542.             
  543.             /* can we combine them?
  544.             NOTE: this is outside the if below because I want to make adding other
  545.             optimizations as easy as possible.   if we decide this is to be all there
  546.             is it should be moved inside. */
  547.             canCombine = (containedObj != NULL)
  548.                     && (op->objClass == (*containedObj)->objClass) ;
  549.             
  550.             /* Now see if there are any optimizations we can make.  Optimizations, in this case,
  551.             mean folding two object records together and combining their selection data into
  552.             a single descriptor.  We attempt to combine the object record associated with
  553.             the current invocation of CreateObj() with that belonging to the invocation that
  554.             called us by folding the necessary stuff into the other and disposing of this one.*/
  555.             
  556.             
  557.             if ( op->u.objForm == formTest )
  558.             {
  559.                 if ( canCombine && ((*containedObj)->u.objForm == formAbsolutePosition)
  560.                     && (((*containedObj)->objSelectionData.descriptorType == typeLongInteger)
  561.                         || (((*containedObj)->objSelectionData.descriptorType
  562.                                 == typeAbsoluteOrdinal)
  563.                                 && IsKnownAbso( **(LongHandle)
  564.                                     (*containedObj)->objSelectionData.dataHandle ) )) )
  565.                 {
  566.                     index.startValue = **((LongHandle)
  567.                             ((*containedObj)->objSelectionData.dataHandle)) ;
  568.                     index.startCase = (*containedObj)->objSelectionData.descriptorType ;        /* was typelongeger */
  569.                     index.stopCase = typeNull ;
  570.                 
  571.                     /* now dispose of the containing obj and fix the pointers */
  572.                     IgnoreOSErr( AEDisposeDesc( &(*containedObj)->objSelectionData ) ) ;
  573.                 }
  574.                 else if ( canCombine && ((*containedObj)->u.objForm == formRange)
  575.                             && RangeIsWhoseable( op->objClass,
  576.                                     (*containedObj)->objSelectionData, &index, &err )
  577.                             && err == noErr )
  578.                 {
  579.                     IgnoreOSErr( AEDisposeDesc( &(*containedObj)->objSelectionData ) ) ;        /* no longer need range */
  580.                 }
  581.                 else if ( err != noErr )            // <eeh> added with port b/c of loss
  582.                 {                                            // of nested procedures
  583.                     goto errExit ;
  584.                 }
  585.                 else
  586.                 {
  587.                     op->u.objForm = formWhose ;
  588.                     index.startCase = typeAbsoluteOrdinal ;
  589.                     index.startValue = (long)kAEAll ;
  590.                     index.stopCase = typeNull ;
  591.                     canCombine = false ;                    /* 4/4 fixes bug where optimization takes place though shouldn't */
  592.                 } 
  593.                 FailErr( AECreateDesc( typeWhoseRangeInternal, (Ptr)&index,
  594.                     sizeof(index), &tempObject ), err, errExit ) ;
  595.                 FailErr( MakeWhoseDescriptor( &tempObject, &op->objSelectionData,
  596.                     &op->objSelectionData ), err, errExit ) ;        /* disposes its inputs */
  597.                 if ( canCombine )            /* really: if ( shouldCombine ... */
  598.                     CombineObjects( &newObj, &containedObj ) ;    /* fold both into 2nd */
  599.             } 
  600.         } // "WITH"
  601.         
  602.         IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  603.         break ;
  604.     
  605.     default :
  606.     /* This is just a token or descriptor. We will not need to resolve
  607.     it further */
  608.     //WITH newObj** DO
  609.         
  610.         /* The question what value to assign class in the case where an obj's type
  611.          * is 
  612.          * really not distinct from its class is related to that of how to tell whether
  613.          * the value of an obj is a token or a descriptor we own.  Or at least the
  614.          * solutions are likely to be related.
  615.         
  616.          * if ( we get here with a token, ) we must pay careful attention to the class
  617.          * as well as the type of the token.  Yet if ( we get here with, say, as desc
  618.          * of type text and data "string" we were probably called by CreateCompare or 
  619.          * somesuch which has little use for the concept of class.  For now, it's
  620.          * probably best to have those routines pass type as class.  But this whose
  621.          * question is really one that could bear some revisitation.  */
  622.         
  623.             (*newObj)->objClass = input->descriptorType ;
  624.         
  625.         /* <eeh> I assume there is no way this could _ever_ be a token */
  626.         {
  627.             // I WANT TO EXACTLY DUPLICATE THE FUNCTIONALITY OF THE COMMENTED OUT STATEMENT
  628.             //    BELOW.
  629.             AEDesc    tempDesc;
  630.             OSErr        error;
  631.             
  632.             error = AEDuplicateDesc(input, &tempDesc);
  633.             ((*newObj)->objValue).descriptorType = tempDesc.descriptorType;
  634.             ((*newObj)->objValue).dataHandle = tempDesc.dataHandle;
  635.             if (error)
  636.                 FailErr(error, err, errExit);
  637.         }
  638.     //        FailErr( AEDuplicateDesc( input, &(*newObj)->objValue ), err, errExit ) ;
  639.             /* caller knows whether to dispose input */
  640.             
  641.             (*newObj)->objRedo = false;
  642.     
  643.         } // switch
  644.     
  645.         /*        IgnoreOSErr( AEDisposeDesc( tempObject )) ;            */
  646.         /*        pAssert( tempObject.dataHandle = NULL, 'was not NULL' ) ;    */
  647.     
  648.         HUnlock( (Handle)newObj ) ;
  649.         *theObject = newObj;
  650.         return err ;
  651.     
  652.     
  653.     FAIL_ERR_PROC(err, errExit)
  654.         if ( newObj != NULL )
  655.         {
  656.             HLock( (Handle)newObj ) ;
  657.     //        WITH newObj** DO
  658.             {
  659.                 ObjRecordPtr op = *newObj ;
  660.                 if ( ! SetErrDesc( op->theObjInput ) )
  661.                     IgnoreOSErr( AEDisposeDesc( &(*newObj)->theObjInput ) ) ;
  662.                 IgnoreOSErr( AEDisposeDesc( &op->objSelectionData ) ) ;    
  663.                 DisposeWhose( (Whose)op->objTheWhose ) ;                    /* <eeh> Do I need this? */
  664.                 DisposeObj( op->objContainer ) ;
  665.             }
  666.             DisposeHandle( (Handle) newObj ) ;
  667.         } 
  668.         IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  669.         IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  670.         *theObject = NULL;
  671.     END_FAIL_ERR_PROC(err)
  672.     
  673. } /*CreateObject*/
  674.  
  675.  
  676.  
  677. void
  678. zero( char *s, long bytes )
  679. {
  680.     while ( bytes-- )
  681.         *s++ = 0 ;
  682. }
  683.  
  684. static OSErr
  685. CreateCompareEvt( AEDesc *input, CompareEvent *output)
  686. {
  687.     CompareEvtRecord cer ;
  688.     OSErr err = noErr ;
  689.     CompareEvent newCompEvnt = NULL ;
  690.     DescType theRtndType ; 
  691.     DescType cEventClass ; 
  692.     DescType cEventID ; 
  693.     long actualSize ;
  694.     ProcessSerialNumber psn = { 0, kCurrentProcess } ;
  695.     AEAddressDesc target ;
  696.     AEDesc params, tempDesc ;
  697.     AEKeyword theAEKeyword ;
  698.     long numElements ;
  699.  
  700.     zero( (char *)&cer, sizeof(cer) ) ;
  701.     params.dataHandle = NULL ;
  702.     target.dataHandle = NULL ;
  703.     tempDesc.dataHandle = NULL ;
  704.  
  705.     FailErr( AECreateDesc( typeProcessSerialNumber, (Ptr)&psn, sizeof(psn),
  706.             &target ), err, errExit ) ;
  707.  
  708.     FailErr( AEGetKeyPtr( input, keyEventClassParam, typeType, 
  709.             &theRtndType, (Ptr)&cEventClass, sizeof(cEventClass), &actualSize ),
  710.             err, errExit ) ;
  711.  
  712.     FailErr( AEGetKeyPtr( input, keyEventIDParam, typeType, 
  713.             &theRtndType, (Ptr)&cEventID, sizeof(cEventID), &actualSize),
  714.             err, errExit ) ;
  715.  
  716.     FailErr( AECreateAppleEvent( cEventClass, cEventID, &target,
  717.             kAutoGenerateReturnID, kAnyTransactionID, &cer.eventWParams ),
  718.             err, errExit ) ;
  719.     
  720.     IgnoreOSErr( AEDisposeDesc( &target ) ) ;
  721.  
  722.     // now move the params from the incomming descriptor to the AppleEvent
  723.     // we'll be sending as the event.
  724.  
  725.     FailErr( AEGetKeyDesc( input, keyCompEvtParams, typeAERecord,
  726.             ¶ms ), err, errExit ) ;
  727.  
  728.     FailErr( AECountItems( ¶ms, &numElements ), err, errExit ) ;
  729.     while ( numElements )
  730.     {
  731.         FailErr( AEGetNthDesc( ¶ms, numElements, typeWildCard,
  732.                 &theAEKeyword, &tempDesc ), err, errExit ) ;
  733.         FailErr( AEPutParamDesc( &cer.eventWParams, theAEKeyword, &tempDesc ),
  734.                 err, errExit ) ;
  735.         IgnoreOSErr( AEDisposeDesc( &tempDesc ) ) ;
  736.         --numElements ;
  737.     }
  738.     IgnoreOSErr( AEDisposeDesc( ¶ms ) ) ;
  739.  
  740.  
  741.     cer.value = false ;
  742.     cer.redo = true ;
  743.     
  744. //    FailErr( AEDuplicateDesc( input, &cer.theCompEvtInput ), err, errExit ) ;
  745.     cer.theCompEvtInput = *input ;
  746.     input->dataHandle = NULL ;                // so the later dispose won't do any harm
  747.  
  748.     DebugStr("\pWarning: PtrToHand being called. Result will be wrong.");
  749.     PtrToHand( &cer, (Handle *)&newCompEvnt, sizeof(cer) ) ;
  750.     FailErr( MemError(), err, errExit ) ;
  751.     
  752.     *output = newCompEvnt ;
  753.         
  754. FAIL_ERR_PROC(err, errExit)
  755.     if ( cer.eventWParams.dataHandle )
  756.         IgnoreOSErr( AEDisposeDesc( &cer.theCompEvtInput ) ) ;
  757.     if ( target.dataHandle )
  758.         IgnoreOSErr( AEDisposeDesc( &target ) ) ;
  759.     if ( tempDesc.dataHandle )
  760.         IgnoreOSErr( AEDisposeDesc( &tempDesc ) ) ;
  761. END_FAIL_ERR_PROC(err)
  762.  
  763. } // CreateCompareEvt
  764.  
  765.  
  766.  
  767.     /*———————————————————————— CreateTerm ————————————————————————*/
  768.  
  769. /*create a term record from either a typeLogicalDescriptor or 
  770.  * a typeCompDescriptor*/
  771. OSErr
  772. CreateTerm( AEDesc  *input, Term *theTerm )
  773. {
  774.     OSErr err = noErr;
  775.     
  776.     FailErr( ClearNewHandle( (Handle *)theTerm, sizeof(TestTermRecord) ),
  777.             err, errExit ) ;
  778.  
  779. /*            Using NewHandleClear saves the following calls:
  780.     WITH theTerm^^ DO
  781.         {
  782.             next := NULL ;
  783.             value := false ;
  784.             redo := false ;
  785.             ttype := kCompare ;
  786.             comp/log := NULL ;
  787.         } ; */
  788.  
  789.     HLock( (Handle) *theTerm ) ;
  790.     FailErr( AEDuplicateDesc( input, &(**theTerm)->theTermInput ), err, errExit ) ;
  791.     
  792. //    WITH theTerm^^ DO
  793.     {
  794.         register TestTermPtr tp = **theTerm ;
  795.         switch ( input->descriptorType )
  796.         {    
  797.             case typeLogicalDescriptor :
  798.                 tp->ttype = kLogical;
  799.                 FailErr( CreateLogical( input, &tp->u.log ), err, errExit ) ;
  800.                 break ;
  801.             case typeCompDescriptor :
  802.                 tp->ttype = kCompare ;
  803.                 FailErr( CreateCompare( *input, &tp->u.compar ), err, errExit ) ;
  804.                 break ;
  805.             case typeCompEvtDescriptor :
  806.                 tp->ttype = kCompareEvt ;
  807.                 FailErr( CreateCompareEvt( input, &tp->u.cEvt ),
  808.                         err, errExit ) ;
  809.                 break ;
  810.             default :
  811.                 err = errAEBadTestKey ;
  812.                 goto errExit ;
  813.         }
  814.                                 
  815.         
  816.         /* set the redo flag so that everything tries to evaluate at least once */
  817.         tp->redo = true;
  818.     }
  819.     
  820.     HUnlock( (Handle) *theTerm ) ;
  821.     IgnoreOSErr( AEDisposeDesc( input ) ) ;
  822.  
  823. FAIL_ERR_PROC(err, errExit)
  824.     if ( *theTerm != NULL )
  825.     {
  826.         if ( SetErrDesc( (**theTerm)->theTermInput ) )    
  827.             (**theTerm)->theTermInput.dataHandle = NULL ;
  828.         if ( (**theTerm)->ttype == kLogical )
  829.             DisposeLogical( (Logical)(**theTerm)->u.log ) ;
  830.         else
  831.             DisposeCompare((Comparison)(**theTerm)->u.compar ) ;
  832.         DisposeTerm( (**theTerm)->next ) ;
  833.     }
  834.     DisposeHandle( (Handle)*theTerm ) ;
  835.     *theTerm = NULL ;
  836. END_FAIL_ERR_PROC(err)
  837.  
  838. }  /* CreateTerm */
  839.  
  840.  
  841.     /*———————————————————————— CreateWhose ————————————————————————*/
  842.  
  843. static OSErr
  844. AdjustIndexValue( long  *result, DescType *specialCase )
  845. {
  846.     if ( *specialCase == typeAbsoluteOrdinal )
  847.     {
  848.         *specialCase = (DescType)*result ;
  849.         *result = 1 ;
  850.  
  851.         if ( *specialCase == kAEFirst )
  852.                 *specialCase = typeLongInteger ;
  853.         else if ( *specialCase == kAELast )
  854.         {
  855.             *specialCase = typeLongInteger ;
  856.             *result = -1 ;
  857.         }
  858.         
  859.         /* Certain special relative forms are not allowed in whose ranges */
  860.         /* <eeh> removed test for kAENext etc.  No longer considered in same class
  861.           as Last, Any etc. */
  862.     }
  863.     else if ( (*specialCase != typeLongInteger) && (*specialCase != typeNull) )
  864.         return errAEImpossibleRange ;
  865.  
  866.     return noErr ;
  867. } // AdjustIndexValue
  868.  
  869.  
  870.  
  871.  
  872. OSErr
  873. CreateWhose( AEDesc  input ,        /* do not dispose: may be a whose descriptor an accessor expects to use later */
  874.             Whose *theWhose )
  875.         /*create a Whose record by unpacking the whose descriptor in a range*/
  876. {        
  877.     AEDesc         tempObject ;
  878.     AEDesc         tempRecord ;
  879. //    DescType         theReturnedType ;            not used in Pascal original
  880. //    Size         actualSize ;                            same here
  881.     OSErr err = noErr ;
  882.             
  883.         tempObject.dataHandle = NULL;
  884.         tempRecord.dataHandle = NULL;
  885.         
  886.         FailErr( ClearNewHandle( (Handle *)theWhose, sizeof(WhoseRecord) ),
  887.                 err, errExit ) ;
  888.  
  889. /*            Using NewHandleClear saves the following calls:
  890.         WITH theWhose^^ DO
  891.             {
  892.                 index.start := 0 ;
  893.                 index.stop := 0 ;
  894.                 theTerm := NULL ;
  895.                 value.dataHandle := NULL ;
  896.             } ;
  897. */
  898.  
  899.         HLock( (Handle) *theWhose ) ;
  900.         FailErr( AEDuplicateDesc( &input, &(**theWhose)->theWhoseInput ),
  901.                 err, errExit ) ;
  902.         
  903.         FailErr( AECoerceDesc( &input, typeAERecord, &tempRecord ),
  904.                 err, errExit ) ;
  905.  
  906. //            WITH theWhose^^ DO
  907.         {
  908.             WhoseRecordPtr wpr = **theWhose ;                
  909.  
  910.             /*get the selector data, and if ( it is a whose ) create the Whose record*/
  911.             FailErr( AEGetKeyDesc( &tempRecord, keyAETest, typeWildCard,
  912.                 &tempObject ), err, errExit ) ;
  913.             FailErr( CreateTerm( &tempObject, &wpr->theTerm ),
  914.                     err, errExit) ;
  915.  
  916.             FailErr( AEGetKeyDesc( &tempRecord, keyAEIndex, typeWildCard,
  917.                     &tempObject ), err, errExit ) ;
  918.  
  919.             if ( tempObject.descriptorType == typeWhoseRangeInternal )
  920.             {
  921.                 BlockMove( *(tempObject.dataHandle), (Ptr)&wpr->index,
  922.                         sizeof(wpr->index) ) ;
  923.                 FailErr( AdjustIndexValue( &wpr->index.startValue,
  924.                     &wpr->index.startCase ), err, errExit ) ;
  925.                 FailErr( AdjustIndexValue( &wpr->index.stopValue,
  926.                     &wpr->index.stopCase ), err, errExit )
  927.             }
  928.             else
  929.             {
  930.                 wpr->index.startValue = **((LongHandle)tempObject.dataHandle) ;
  931.                 wpr->index.startCase = tempObject.descriptorType ;
  932.                 FailErr( AdjustIndexValue( &wpr->index.startValue, 
  933.                         &wpr->index.startCase ), err, errExit ) ;
  934.                 wpr->index.stopCase = typeNull ;
  935.             }
  936.         
  937.             IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  938.             IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  939.         }
  940.         
  941.         HUnlock( (Handle) *theWhose ) ;
  942.  
  943. FAIL_ERR_PROC(err, errExit)
  944.     if ( *theWhose != NULL )
  945.     {
  946.         if ( SetErrDesc( (**theWhose)->theWhoseInput ) )
  947.             (**theWhose)->theWhoseInput.dataHandle = NULL ;
  948.         DisposeTerm( (**theWhose)->theTerm ) ;
  949.     }
  950.     IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  951.     IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  952.     DisposeHandle( (Handle)*theWhose ) ;
  953.     *theWhose = NULL;
  954. END_FAIL_ERR_PROC(err)
  955.  
  956. } /*CreateWhose*/
  957.         
  958.